package com.fire.eyes.controller;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.fire.core.mode.TMitUserToken;
import com.fire.core.service.RedisService;
import com.fire.core.util.AjaxResult;
import com.fire.eyes.constants.ErrorCodeConstants;
import com.fire.eyes.model.*;
import com.fire.eyes.service.*;
import com.fire.eyes.validation.AssetEventDTO;
import com.fire.eyes.validation.DispelAlertDTO;
import com.fire.eyes.validation.TokenDTO;
import com.smartthing.rest.model.device.event.DeviceAlert;
import com.smartthing.rest.model.device.event.DeviceLocation;
import com.smartthing.rest.model.device.event.DeviceMeasurements;
import com.smartthing.rest.model.search.*;
import com.smartthing.spi.ISmartThingClient;
import com.smartthing.spi.SmartThingException;
import com.smartthing.spi.device.DeviceAssignmentType;
import com.smartthing.spi.device.event.AlertLevel;
import com.smartthing.spi.device.event.AlertSource;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.*;

@RestController
public class EventController {
	private final static Logger logger = Logger.getLogger(EventController.class);
	private final static String YES = "YES";
	//private final static String SMARTTHING = "SmartThing";
	@Autowired
	private ISiteService siteService;
	@Autowired
	private SolrClient client;
	@Autowired
	private IRecordAlarmService recordAlarmService;
	@Autowired
	private RedisService redisService;
	@Autowired
	private IUserAuthorityService userAuthorityService;
	@Autowired
	private IFireProprietorUserService fireProprietorUserService;
	@Autowired
	private IFireMaintainUserService fireMaintainUserService;
	@Autowired
	private IFireSupervisorUserService fireSupervisorUserService;
	@Autowired
	private ISmartThingClient smartThingClient;
	@Value("${spring.data.solr.core}")
	private String core;

	/**
	 * 查询消防资产事件链表
	 *
	 * @return
	 * @author zengzhengfu
	 */
	@PostMapping(value = "/dispelalert")
	@ResponseBody
	public AjaxResult dispelalert(@RequestBody @Validated DispelAlertDTO dispelAlertDTO, BindingResult bindingResult) {
		if (bindingResult.hasErrors()) {
			for (FieldError fieldError : bindingResult.getFieldErrors()) {
				String message = fieldError.getDefaultMessage();
				logger.error(message);
				return new AjaxResult(ErrorCodeConstants.PARAM_WRONGFULL, "参数有误," + message, "参数有误," + message);
			}
		}

		TMitUserToken userToken = (TMitUserToken) redisService.get(dispelAlertDTO.getToken());
		String alertid = dispelAlertDTO.getAlertid();
		try {
			SolrQuery params = new SolrQuery();
			//查询条件
			params.set("q", "eventId:" + alertid);

			//yml文件未配置具体的collection，所以此处需要配置
			QueryResponse queryResponse = client.query(core, params);

			SolrDocumentList results = queryResponse.getResults();
			SolrDocument entries = results.get(0);
			//入库
			RecordAlarmModel recordAlarmModel = new RecordAlarmModel();
			recordAlarmModel.setAlertid((String) entries.get("eventId"));
			recordAlarmModel.setEventType("Alert");
			recordAlarmModel.setDeviceAssignmentToken((String) entries.get("assignmentToken"));
			recordAlarmModel.setDeviceAssignmentType((String) entries.get("assignmentType"));
			recordAlarmModel.setAssetId((String) entries.get("assetId"));
			recordAlarmModel.setSiteToken((String) entries.get("siteToken"));
			recordAlarmModel.setEventDate((Date) entries.get("eventDate"));
			recordAlarmModel.setReceivedDate((Date) entries.get("receivedDate"));
			List alertType = (List) entries.get("alertType");
			recordAlarmModel.setType(alertType.toString());
			recordAlarmModel.setMessage((String) entries.get("alertMessage"));
			recordAlarmModel.setLevel((String) entries.get("alertLevel"));
			recordAlarmModel.setSource((String) entries.get("alertSource"));
			recordAlarmModel.setCreatetime(new Date());
			recordAlarmModel.setOperattime(new Date());
			recordAlarmModel.setOperator(userToken.getAliasname());
			recordAlarmModel.setSpotimage(dispelAlertDTO.getSpotimage());
			recordAlarmModel.setReason(dispelAlertDTO.getReason());

			recordAlarmService.insert(recordAlarmModel);
			//删除记录
			client.deleteById(core, alertid);
			client.commit(core);
			return new AjaxResult(ErrorCodeConstants.SUCCESS, "消除成功", "消除成功");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return new AjaxResult(ErrorCodeConstants.SUCCESS, "消除失败", "消除失败");
	}


	/**
	 * 查询消防资产事件链表
	 *
	 * @return
	 * @author zengzhengfu
	 */
	@PostMapping(value = "/assetevent")
	@ResponseBody
	public AjaxResult assetevent(@RequestBody @Validated({TokenDTO.paging.class}) AssetEventDTO assetEventDTO, BindingResult bindingResult) {
		if (bindingResult.hasErrors()) {
			for (FieldError fieldError : bindingResult.getFieldErrors()) {
				String message = fieldError.getDefaultMessage();
				logger.error(message);
				return new AjaxResult(ErrorCodeConstants.PARAM_WRONGFULL, "参数有误," + message, "参数有误," + message);
			}
		}
		//ISmartThingClient client = new SmartThingClient("http://10.12.8.223:26666/smartthing/api/", "admin", "password");

		if (YES.equals(assetEventDTO.getIsalert())) {
			//历史告警使用接口查询
			if (YES.equals(assetEventDTO.getHistory())) {
				//只有站点id
				return getSiteAlerts(assetEventDTO);
			}
			//非历史告警使用solr查询
			return getSiteAlertsBySolr(assetEventDTO);
		}
		String assetid = assetEventDTO.getAssetid();
		String siteid = assetEventDTO.getSiteid();
		//有资产id，使用solr查询;无站点id，也无资产id，则查询所有事件
		if (StringUtils.isNotBlank(assetEventDTO.getAssetid()) || (StringUtils.isBlank(siteid) && StringUtils.isBlank(assetid))) {
			if (YES.equals(assetEventDTO.getIsmeasurement())) {
				//返回站点测量
				return getSiteMeasurementsBySolr(assetEventDTO);
			} else {
				//返回站点位置
				return getSiteLocationsBySolr(assetEventDTO);
			}
		} else {
			//无资产id，查询站点下的所有位置或测量，使用SmartThing提供的借口查询
			if (YES.equals(assetEventDTO.getIsmeasurement())) {
				//返回站点测量
				return getSiteMeasurements(assetEventDTO);
			} else {
				//返回站点位置
				return getSiteLocations(assetEventDTO);
			}
		}
		//return new AjaxResult(ErrorCodeConstants.SUCCESS, "获取失败", "获取失败");
	}


	private AjaxResult getSiteAlertsBySolr(AssetEventDTO assetEventDTO) {
		System.out.println("====================通过solr查询告警start==============================");
		try {
			SolrQuery params = new SolrQuery();
			//查询条件
			StringBuilder multi_params = new StringBuilder("eventType:Alert");
			params = getParams(params, assetEventDTO, multi_params);
			logger.info("查询Alerts条件："+params.toString());
			System.out.println("查询Alerts条件："+params.toString());
			//yml文件未配置具体的collection，所以此处需要配置
			QueryResponse queryResponse = client.query(core, params);

			SolrDocumentList results = queryResponse.getResults();
			System.out.println("查询Alerts结果："+results.toString());

			DeviceAlertSearchResults searchResults = new DeviceAlertSearchResults();
			searchResults.setNumResults(results.getNumFound());
			List<DeviceAlert> responseResult = new ArrayList<>();
			for (SolrDocument document : results) {
				DeviceAlert alert = new DeviceAlert();

				alert.setId((String) document.get("eventId"));
				alert.setDeviceAssignmentToken((String) document.get("assignmentToken"));

				String assignmentType = (String) document.get("assignmentType");
				DeviceAssignmentType assignmentTypeEnum = (DeviceAssignmentType) getEnum(assignmentType, DeviceAssignmentType.values());
				alert.setAssignmentType(assignmentTypeEnum);

				String assetId = (String) document.get("assetId");
				alert.setAssetId(assetId);
				String siteToken = (String) document.get("siteToken");
				alert.setSiteToken(siteToken);

				Date eventDate = (Date) document.get("eventDate");
				alert.setEventDate(eventDate);
				Date receivedDate = (Date) document.get("receivedDate");
				alert.setReceivedDate(receivedDate);

				alert.setType(document.get("alertType").toString());
				alert.setMessage((String) document.get("alertMessage"));
				String level = (String) document.get("alertLevel");
				AlertLevel alertEnum = (AlertLevel) getEnum(level, AlertLevel.values());
				alert.setLevel(alertEnum);
				String alertSource = (String) document.get("alertSource");
				AlertSource sourceEnum = (AlertSource) getEnum(alertSource, AlertSource.values());
				alert.setSource(sourceEnum);
				Map meta = getmetadata(document, "meta");
				alert.setMetadata(meta);
				responseResult.add(alert);
			}

			searchResults.setResults(responseResult);
			System.out.println("====================通过solr查询告警end==============================");
			return new AjaxResult(ErrorCodeConstants.SUCCESS, "获取成功", searchResults, "获取成功");
		} catch (SolrServerException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	private AjaxResult getSiteMeasurementsBySolr(AssetEventDTO assetEventDTO) {
		System.out.println("====================通过solr查询测量信息start==============================");
		try {
			SolrQuery params = new SolrQuery();
			//查询条件
			StringBuilder multi_params = new StringBuilder("eventType:Measurements");

			params = getParams(params, assetEventDTO, multi_params);
			logger.info("查询Measurements条件："+params.toString());
			System.out.println("查询Measurements条件："+params.toString());
			//yml文件未配置具体的collection，所以此处需要配置
			QueryResponse queryResponse = client.query(core, params);

			SolrDocumentList results = queryResponse.getResults();
			System.out.println("查询Measurements结果："+results.toString());
			DeviceMeasurementsSearchResults searchResults = new DeviceMeasurementsSearchResults();
			searchResults.setNumResults(results.getNumFound());
			List<DeviceMeasurements> responseResult = new ArrayList<>();
			for (SolrDocument document : results) {
				DeviceMeasurements measurements = new DeviceMeasurements();

				measurements.setId((String) document.get("eventId"));
				measurements.setDeviceAssignmentToken((String) document.get("assignmentToken"));

				String assignmentType = (String) document.get("assignmentType");
				DeviceAssignmentType assignmentTypeEnum = (DeviceAssignmentType) getEnum(assignmentType, DeviceAssignmentType.values());
				measurements.setAssignmentType(assignmentTypeEnum);

				String assetId = (String) document.get("assetId");
				measurements.setAssetId(assetId);
				String siteToken = (String) document.get("siteToken");
				measurements.setSiteToken(siteToken);

				Date eventDate = (Date) document.get("eventDate");
				measurements.setEventDate(eventDate);
				Date receivedDate = (Date) document.get("receivedDate");
				measurements.setReceivedDate(receivedDate);

				Map provider = getmetadata(document, "mx");
				measurements.setMeasurements(provider);

				Map meta = getmetadata(document, "meta");
				measurements.setMetadata(meta);
				responseResult.add(measurements);
			}

			searchResults.setResults(responseResult);
			System.out.println("====================通过solr查询测量信息end==============================");
			return new AjaxResult(ErrorCodeConstants.SUCCESS, "获取成功", searchResults, "获取成功");
		} catch (SolrServerException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	private AjaxResult getSiteLocationsBySolr(AssetEventDTO assetEventDTO) {
		System.out.println("====================通过solr查询位置信息start==============================");

		try {
			SolrQuery params = new SolrQuery();
			//查询条件
			StringBuilder multi_params = new StringBuilder("eventType:Measurements");
			logger.info("查询Location条件："+params.toString());
			System.out.println("查询Location条件："+params.toString());
			params = getParams(params, assetEventDTO, multi_params);

			//yml文件未配置具体的collection，所以此处需要配置
			QueryResponse queryResponse = client.query(core, params);
			SolrDocumentList results = queryResponse.getResults();
			System.out.println("查询Location结果："+results.toString());

			DeviceLocationSearchResults searchResults = new DeviceLocationSearchResults();
			searchResults.setNumResults(results.getNumFound());
			List<DeviceLocation> responseResult = new ArrayList<>();
			for (SolrDocument document : results) {
				DeviceLocation location = new DeviceLocation();

				location.setId((String) document.get("eventId"));
				location.setDeviceAssignmentToken((String) document.get("assignmentToken"));

				String assignmentType = (String) document.get("assignmentType");
				DeviceAssignmentType assignmentTypeEnum = (DeviceAssignmentType) getEnum(assignmentType, DeviceAssignmentType.values());
				location.setAssignmentType(assignmentTypeEnum);

				String assetId = (String) document.get("assetId");
				location.setAssetId(assetId);
				String siteToken = (String) document.get("siteToken");
				location.setSiteToken(siteToken);

				Date eventDate = (Date) document.get("eventDate");
				location.setEventDate(eventDate);
				Date receivedDate = (Date) document.get("receivedDate");
				location.setReceivedDate(receivedDate);

				List ll = (List) document.get("location");
				String latitude_longitude = ll.get(0).toString();
				String[] split = latitude_longitude.split(",");
				Double latitude = Double.parseDouble(split[0]);
				Double longitude = Double.parseDouble(split[1]);
				location.setLatitude(latitude);
				location.setLongitude(longitude);

				Double elevation = (Double) document.get("elevation");
				location.setElevation(elevation);

				Map meta = getmetadata(document, "meta");
				location.setMetadata(meta);
				responseResult.add(location);
			}

			searchResults.setResults(responseResult);
			System.out.println("====================通过solr查询位置信息end==============================");
			return new AjaxResult(ErrorCodeConstants.SUCCESS, "获取成功", searchResults, "获取成功");
		} catch (SolrServerException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	private Map getmetadata(SolrDocument document, String meta) {
		Map result = new HashMap();
		for (Map.Entry<String, Object> entry : document) {
			if (entry.getKey().contains(meta)) {
				result.put(entry.getKey().replace(meta + ".", ""), entry.getValue());
			}
		}
		return result;
	}

	private Enum getEnum(String level, Enum[] values) {
		for (Enum a : values) {
			if (level.equals(a.toString())) {
				return a;
			}
		}
		return null;
	}

	private SolrQuery getParams(SolrQuery params, AssetEventDTO assetEventDTO, StringBuilder multi_params) {
		TMitUserToken userToken = (TMitUserToken) redisService.get(assetEventDTO.getToken());
		UserAuthorityModel userAuthorityModel = userAuthorityService.selectById(userToken.getUserid());
		String authority = userAuthorityModel.getAuthority();
		List<SiteModel> siteList = new ArrayList();
		switch (authority) {
			case "proprietor":
				FireProprietorUserModel fireProprietorUserModel = fireProprietorUserService.selectById(userToken.getUserid());
				siteList = siteService.selectList(new EntityWrapper<SiteModel>().eq("proprietor", fireProprietorUserModel.getProprietor()));
				break;
			case "supervisor":
				FireSupervisorUserModel fireSupervisorUserModel = fireSupervisorUserService.selectById(userToken.getUserid());
				siteList = siteService.selectList(new EntityWrapper<SiteModel>().eq("supervisorid", fireSupervisorUserModel.getSupervisor()));
				break;
			case "maintainor":
				FireMaintainUserModel fireMaintainUserModel = fireMaintainUserService.selectById(userToken.getUserid());
				siteList = siteService.selectList(new EntityWrapper<SiteModel>().eq("maintainor", fireMaintainUserModel.getMaintainor()));
				break;
		}

		for (int i = 0; i < siteList.size(); i++) {
			if (siteList.size() == 1) {
				multi_params.append(" AND siteToken:" + siteList.get(i).getSitetoken());
				break;
			}
			if (i == 0) {
				multi_params.append(" AND siteToken:(" + siteList.get(i).getSitetoken());
			} else if (i == siteList.size() - 1) {
				multi_params.append(" OR " + siteList.get(i).getSitetoken() + ")");
			} else {
				multi_params.append(" OR " + siteList.get(i).getSitetoken());
			}
		}
		String param_assetId = assetEventDTO.getAssetid();
		if (StringUtils.isNotBlank(param_assetId)) {
			multi_params.append(" AND assetId:" + param_assetId);
		}

		//分页,page=1,pagesize=0的时候查询所有
		if (assetEventDTO.getPage() == 1 && assetEventDTO.getPagesize() == 0) {
			params.setStart(assetEventDTO.getPage() - 1);
			params.setRows(Integer.MAX_VALUE);
		} else {
			params.setStart((assetEventDTO.getPage() - 1) * assetEventDTO.getPagesize());
			params.setRows(assetEventDTO.getPagesize());
		}

		params.setQuery(multi_params.toString());
		return params;
	}

	//以下方法为通过接口查询
	private AjaxResult getSiteAlerts(AssetEventDTO assetEventDTO) {
		DateRangeSearchCriteria criteria = new DateRangeSearchCriteria(assetEventDTO.getPage(), assetEventDTO.getPagesize(), null, null);
		DeviceAlertSearchResults searchResults = null;
		SiteModel siteModel = siteService.selectById(assetEventDTO.getSiteid());
		try {
			//searchResults = client.listDeviceLocationsForSite("bb105f8d-3150-41f5-b9d1-db04965668d3", criteria);
			searchResults = smartThingClient.listDeviceAlertsForSite(siteModel.getSitetoken(), criteria);
		} catch (SmartThingException e) {
			e.printStackTrace();
			return new AjaxResult(ErrorCodeConstants.INTERNAL_ERROR, "系统内部错误", searchResults, "系统内部错误");
		}
		return new AjaxResult(ErrorCodeConstants.SUCCESS, "获取成功", searchResults, "获取成功");
	}

	private AjaxResult getSiteLocations(AssetEventDTO assetEventDTO) {
		DateRangeSearchCriteria criteria = new DateRangeSearchCriteria(assetEventDTO.getPage(), assetEventDTO.getPagesize(), null, null);
		DeviceLocationSearchResults searchResults = null;
		SiteModel siteModel = siteService.selectById(assetEventDTO.getSiteid());
		try {
			//searchResults = client.listDeviceLocationsForSite("bb105f8d-3150-41f5-b9d1-db04965668d3", criteria);
			searchResults = smartThingClient.listDeviceLocationsForSite(siteModel.getSitetoken(), criteria);
		} catch (SmartThingException e) {
			e.printStackTrace();
			return new AjaxResult(ErrorCodeConstants.INTERNAL_ERROR, "系统内部错误", searchResults, "系统内部错误");
		}
		return new AjaxResult(ErrorCodeConstants.SUCCESS, "获取成功", searchResults, "获取成功");
	}

	private AjaxResult getSiteMeasurements(AssetEventDTO assetEventDTO) {
		DateRangeSearchCriteria criteria = new DateRangeSearchCriteria(assetEventDTO.getPage(), assetEventDTO.getPagesize(), null, null);
		DeviceMeasurementsSearchResults searchResults = null;
		SiteModel siteModel = siteService.selectById(assetEventDTO.getSiteid());
		try {
			//searchResults = client.listDeviceMeasurementsForSite("bb105f8d-3150-41f5-b9d1-db04965668d3", criteria);
			searchResults = smartThingClient.listDeviceMeasurementsForSite(siteModel.getSitetoken(), criteria);
		} catch (SmartThingException e) {
			e.printStackTrace();
			return new AjaxResult(ErrorCodeConstants.INTERNAL_ERROR, "系统内部错误", searchResults, "系统内部错误");
		}
		return new AjaxResult(ErrorCodeConstants.SUCCESS, "获取成功", searchResults, "获取成功");
	}

	public static void main(String[] args) throws Exception {
		/*ISmartThingClient client = new SmartThingClient("http://10.12.8.223:26666/smartthing/api/", "admin", "password");
		DateRangeSearchCriteria criteria = new DateRangeSearchCriteria(1, 10, null, null);
		DeviceMeasurementsSearchResults searchResults = client.listDeviceMeasurementsForSite("bb105f8d-3150-41f5-b9d1-db04965668d3", criteria);
		//DeviceLocationSearchResults searchResults = client.listDeviceLocationsForSite("bb105f8d-3150-41f5-b9d1-db04965668d3", criteria);
		System.out.println(searchResults.getResults().size());*/
	}
}
